package rmbfxmarket;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

import repast.simphony.random.RandomHelper;
import java.util.Random;
import repast.simphony.engine.environment.RunEnvironment;
import repast.simphony.parameter.Parameters;

public class Customer {
  private int type; //the initial type of the agent; it is 0 , then the customer must buy or sell foreigh money
                    // if it is 1, the customer is technical dealer
                    // if it is 2, the customer is fundamental dealer
  private int ID;   //the ID of the customer
  private double demand;
  public ArrayList<RMBFXBankMemberAgent> BKMlist; //the bank member the customer belongs
  private double alpha; 
  private double beta;
  private double eta;
  private double currentExchangeRate=0;
  private double previousExchangeRate=0;
  private double previousTwoExchangeRate=0;
  private double currentProfit;
  private double previousProfit;
  private double initiaOfFittness;
  private double demandTechnicalPrivious;
  private double demandfundmentalPrivious;
  private double fixedDemand;
  private double fittnessOfTechnical;
  private double fittnessOfFundmental;
  private double previousFittnessOfTechnical;
  private double previousFittnessOfFundmental;
  private double FundamantleExchangeRate;
  
  public Customer() {
	  //System.out.println("The creation of Customer agent");  
	  Parameters p = RunEnvironment.getInstance().getParameters();
	  alpha=(Double) p.getValue("alpha");   // the coefficient of demand function of 
	  beta=(Double) p.getValue("beta");
	  eta=(Double ) p.getValue("eta");
	  initiaOfFittness=(Double ) p.getValue("initiaOfFittness");
	  FundamantleExchangeRate=(Double ) p.getValue("FundamantleExchangeRate");
	  BKMlist=new ArrayList(); 
	  BKMlist.clear();
  }
  
  class orderOfCustomer{
  	int IDOfCustomer;  // ID
  	double order;       //the oder sell or buy demand  forward to BKM
  }
  
  //get current exchange rate buy and sell from the attached BKM
  public void getExchangeRateFromBKM(){
	  //here, we assume customer only has one BKM to commit demand
	  RMBFXBankMemberAgent BKM=BKMlist.get(0);
	  currentExchangeRate=BKM.getCurrentExchangeRate();
	  //System.out.println("currentExchangeRate    "+currentExchangeRate);
  }  
  //compute the fitness of agent type 
  private void computeFitness(){
	   fittnessOfTechnical=previousFittnessOfTechnical* initiaOfFittness+(previousExchangeRate-previousTwoExchangeRate)*demandTechnicalPrivious;
	   fittnessOfFundmental=previousFittnessOfFundmental* initiaOfFittness+(previousExchangeRate-previousTwoExchangeRate)*demandfundmentalPrivious;
  }
  
  //agent may change his type in the simulation due to the different revenue he gets
  private void chooseAgentType(){
	    double fittnessOfTechnical=0;                          
		double fittnessOfFundmental=0; 
		double probabilityOfTech=0;
		double probabilityOfFund=0;
		double eta=0;                                                
		computeFitness();	//first, compute the fitness of different strategies
	    int  t = (int) RunEnvironment.getInstance().getCurrentSchedule().getTickCount();
	    if ((t==1) || (t==2)){
	    	return;
			}
		 else
		 {
		   probabilityOfTech=Math.exp(fittnessOfTechnical*eta)/(Math.exp(fittnessOfFundmental*eta)+Math.exp(fittnessOfTechnical*eta));
		   probabilityOfFund=Math.exp(fittnessOfFundmental*eta)/(Math.exp(fittnessOfFundmental*eta)+Math.exp(fittnessOfTechnical*eta));
	      }
	    
	    double randomProb=RandomHelper.nextDoubleFromTo(0, 1);    
	    if (randomProb<probabilityOfTech)type=1;
	    else type=2;
     }
  
  // compute the demand according the type and price change if this agent is not a fixed demand customer
  public void decideDemand(){
	  if (type==1) {
		  demand=(previousExchangeRate-previousTwoExchangeRate)*alpha;
	  }
	  else if(type==2){
		  demand=(FundamantleExchangeRate-previousExchangeRate)*beta;
	  }
	  else if(type==0){
		  demand=fixedDemand;
	  }
	// System.out.println(previousExchangeRate+"  "+previousTwoExchangeRate+"  "+FundamantleExchangeRate+"   "+previousExchangeRate );
  }
  
  // commit the demand to the attached Bank member 
  public void commitTracWithBKM(){
	  orderOfCustomer order=new  orderOfCustomer();
	  order.order=demand;
	  order.IDOfCustomer=this.ID;
	  //System.out.println("BKMlist  size is     "+BKMlist.size());
	  RMBFXBankMemberAgent BKM=BKMlist.get(0);
	  //System.out.println("Send the demand to BKM:    "+demand+"  type    "+type);
	  BKM.receiveDemandFromCustomer(order);
	  
  }
  
  public void post(){
	  previousExchangeRate=currentExchangeRate;
	  previousTwoExchangeRate=previousExchangeRate;
	  previousProfit=currentProfit;
	  previousFittnessOfTechnical=fittnessOfTechnical;
	  previousFittnessOfFundmental=fittnessOfFundmental;
  }

public int getType() {
	return type;  
}

/**
 * @param type the type to set
 */
public void setType(int type) {
	this.type = type;
}

/**
 * @return the iD
 */
public int getID() {
	return ID;
}

/**
 * @param id the iD to set
 */
public void setID(int id) {
	ID = id;
}

/**
 * @return the demand
 */
public double getDemand() {
	return demand;
}

/**
 * @param demand the demand to set
 */
public void setDemand(double demand) {
	this.demand = demand;
}

/**
 * @return the bKMlist
 */
public ArrayList<RMBFXBankMemberAgent> getBKMlist() {
	return BKMlist;
}

/**
 * @param mlist the bKMlist to set
 */
public void setBKMlist(ArrayList<RMBFXBankMemberAgent> mlist) {
	BKMlist = mlist;
}

/**
 * @return the alpha
 */
public double getAlpha() {
	return alpha;
}

/**
 * @param alpha the alpha to set
 */
public void setAlpha(double alpha) {
	this.alpha = alpha;
}

/**
 * @return the beta
 */
public double getBeta() {
	return beta;
}

/**
 * @param beta the beta to set
 */
public void setBeta(double beta) {
	this.beta = beta;
}

/**
 * @return the eta
 */
public double getEta() {
	return eta;
}

/**
 * @param eta the eta to set
 */
public void setEta(double eta) {
	this.eta = eta;
}

/**
 * @return the currentExchangeRate
 */
public double getCurrentExchangeRate() {
	return currentExchangeRate;
}

/**
 * @param currentExchangeRate the currentExchangeRate to set
 */
public void setCurrentExchangeRate(double currentExchangeRate) {
	this.currentExchangeRate = currentExchangeRate;
}

/**
 * @return the previousExchangeRate
 */
public double getPreviousExchangeRate() {
	return previousExchangeRate;
}

/**
 * @param previousExchangeRate the previousExchangeRate to set
 */
public void setPreviousExchangeRate(double previousExchangeRate) {
	this.previousExchangeRate = previousExchangeRate;
}

/**
 * @return the previousTwoExchangeRate
 */
public double getPreviousTwoExchangeRate() {
	return previousTwoExchangeRate;
}

/**
 * @param previousTwoExchangeRate the previousTwoExchangeRate to set
 */
public void setPreviousTwoExchangeRate(double previousTwoExchangeRate) {
	this.previousTwoExchangeRate = previousTwoExchangeRate;
}

/**
 * @return the currentProfit
 */
public double getCurrentProfit() {
	return currentProfit;
}

/**
 * @param currentProfit the currentProfit to set
 */
public void setCurrentProfit(double currentProfit) {
	this.currentProfit = currentProfit;
}

/**
 * @return the previousProfit
 */
public double getPreviousProfit() {
	return previousProfit;
}

/**
 * @param previousProfit the previousProfit to set
 */
public void setPreviousProfit(double previousProfit) {
	this.previousProfit = previousProfit;
}

/**
 * @return the initiaOfFittness
 */
public double getInitiaOfFittness() {
	return initiaOfFittness;
}

/**
 * @param initiaOfFittness the initiaOfFittness to set
 */
public void setInitiaOfFittness(double initiaOfFittness) {
	this.initiaOfFittness = initiaOfFittness;
}

/**
 * @return the demandTechnicalPrivious
 */
public double getDemandTechnicalPrivious() {
	return demandTechnicalPrivious;
}

/**
 * @param demandTechnicalPrivious the demandTechnicalPrivious to set
 */
public void setDemandTechnicalPrivious(double demandTechnicalPrivious) {
	this.demandTechnicalPrivious = demandTechnicalPrivious;
}

/**
 * @return the demandfundmentalPrivious
 */
public double getDemandfundmentalPrivious() {
	return demandfundmentalPrivious;
}

/**
 * @param demandfundmentalPrivious the demandfundmentalPrivious to set
 */
public void setDemandfundmentalPrivious(double demandfundmentalPrivious) {
	this.demandfundmentalPrivious = demandfundmentalPrivious;
}

/**
 * @return the fittnessOfTechnical
 */
public double getFittnessOfTechnical() {
	return fittnessOfTechnical;
}

/**
 * @param fittnessOfTechnical the fittnessOfTechnical to set
 */
public void setFittnessOfTechnical(double fittnessOfTechnical) {
	this.fittnessOfTechnical = fittnessOfTechnical;
}

/**
 * @return the fittnessOfFundmental
 */
public double getFittnessOfFundmental() {
	return fittnessOfFundmental;
}

/**
 * @param fittnessOfFundmental the fittnessOfFundmental to set
 */
public void setFittnessOfFundmental(double fittnessOfFundmental) {
	this.fittnessOfFundmental = fittnessOfFundmental;
}

/**
 * @return the previousFittnessOfTechnical
 */
public double getPreviousFittnessOfTechnical() {
	return previousFittnessOfTechnical;
}

/**
 * @param previousFittnessOfTechnical the previousFittnessOfTechnical to set
 */
public void setPreviousFittnessOfTechnical(double previousFittnessOfTechnical) {
	this.previousFittnessOfTechnical = previousFittnessOfTechnical;
}

/**
 * @return the previousFittnessOfFundmental
 */
public double getPreviousFittnessOfFundmental() {
	return previousFittnessOfFundmental;
}

/**
 * @param previousFittnessOfFundmental the previousFittnessOfFundmental to set
 */
public void setPreviousFittnessOfFundmental(double previousFittnessOfFundmental) {
	this.previousFittnessOfFundmental = previousFittnessOfFundmental;
}

/**
 * @return the fundamantleExchangeRate
 */
public double getFundamantleExchangeRate() {
	return FundamantleExchangeRate;
}

/**
 * @param fundamantleExchangeRate the fundamantleExchangeRate to set
 */
	public void setFundamantleExchangeRate(double fundamantleExchangeRate) {
	FundamantleExchangeRate = fundamantleExchangeRate;
	}

/**
 * @return the fixedDemand
 */
public double getFixedDemand() {
	return fixedDemand;
}

/**
 * @param fixedDemand the fixedDemand to set
 */
public void setFixedDemand(double fixedDemand) {
	this.fixedDemand = fixedDemand;
}

}